/**
 * @class 矮行星实体
 * @author DuskyHuang 圣子
 * @description 对外视看做为一颗行星对象，对内管理自身行为和表现。
*/

import { _decorator, MeshRenderer, Material, Mesh, pseudoRandom, pseudoRandomRangeInt } from 'cc';
import { NOTFOUND_SHEET_ID, Res } from 'const';
import { calcLensBias, calcTiling } from 'algorithms';
import { Orbiter } from './orbiter';
import { Planet } from './planet';
import { core } from 'cfw';
import { Task, TaskNames } from 'notifications';
import { loadCelTexture } from 'helpers';
const { ccclass, property } = _decorator;

declare type dsm = Extract<orbit, 'dwarf' | 'satellite' | 'minor'>

@ccclass('cocosmos.DwarfSatelliteMinor')
export class Dsm extends Orbiter {

    @property([Material]) public LOD0SharedMats: Material[] = [];
    @property([Material]) public LOD1SharedMats: Material[] = [];
    @property([Material]) public LOD2SharedMats: Material[] = [];
    @property(Mesh) public LOD0MeshIrr: Mesh = null;
    @property(Mesh) public LOD1MeshIrr: Mesh = null;
    @property(Mesh) public LOD0MeshSph: Mesh = null;
    @property(Mesh) public LOD1MeshSph: Mesh = null;
    @property(MeshRenderer) public mesh0: MeshRenderer;
    @property(MeshRenderer) public mesh1: MeshRenderer;
    @property(MeshRenderer) public mesh2: MeshRenderer;

    declare protected _config: dsmConfig;
    public get config(): dsmConfig { return this._config as dsmConfig; }
    protected readonly rotatable: boolean = true;
    protected readonly important: boolean = false;
    public get cat(): dsm { return this._type; }
    public get sphere(): boolean { return this._config.sphere ?? true; }
    protected get LODValves(): num.pct[] { return LOD_VALUES[this.cat]; };


    public setType(type: dsm): void {
        this._type = type;
    }

    protected init(): void {
        super.init();
    }

    protected step(span: time.sec): void {
        super.step(span);
        if (this._lod2) this.faceToSun(this._lod2);
    }

    public configure(): void {
        this._loadMeshParams();
        this._loadLODParams();
        this._bias = calcLensBias(this.config.diam, SMALLEST, BIGGEST, NEAREST, FARTHEST);
    }

    protected onEnable(): void {
        this.mesh0.mesh = this.mesh0.mesh;
        this.mesh1.mesh = this.mesh1.mesh;
    }

    private _loadMeshParams(): void {
        const { sphere = true } = this._config;
        if (sphere) {
            this.mesh0.mesh = this.LOD0MeshSph;
            this.mesh1.mesh = this.LOD1MeshSph;
        } else {
            this.mesh0.mesh = this.LOD0MeshIrr;
            this.mesh1.mesh = this.LOD1MeshIrr;
        }
    }

    private _loadLODParams(): void {
        const { sheet, lod } = this._config;
        if (sheet == NOTFOUND_SHEET_ID) {
            this._tiling = null;
            this.mesh0.setSharedMaterial(this.LOD0SharedMats.tail, 0);
            this.mesh1.setSharedMaterial(this.LOD1SharedMats.tail, 0);
            this.mesh2.setSharedMaterial(this.LOD2SharedMats.tail, 0);
        } else {
            this._tiling = calcTiling(lod, sheet <= 1 ? DSM01_LOD_GIRDS : DSM2_LOD_GIRDS);
            this.mesh0.setSharedMaterial(this.LOD0SharedMats[sheet], 0);
            this.mesh1.setSharedMaterial(this.LOD1SharedMats[sheet], 0);
            this.mesh2.setSharedMaterial(this.LOD2SharedMats[sheet], 0);
        }
    }

    protected syncInstancing(): void {
        if (this._tiling) {
            this.mesh0.setInstancedAttribute('instanced_uv', this._tiling);
            this.mesh1.setInstancedAttribute('instanced_uv', this._tiling);
            this.mesh2.setInstancedAttribute('instanced_uv', this._tiling);
        }
    }

    protected initPhysicsParams(base: pow10): void {
        super.initPhysicsParams(base);
        if (this.cat === 'satellite') {
            const { northPoleRightAscension, rotateObliquity } = this._belong! as Planet;
            this.longitudeOfNode += northPoleRightAscension;
            this.orbitalObliquity -= rotateObliquity;
        }
        if (notEmptyArr(this._config.xyz)) {
            const [rx, ry, rz] = this._config.xyz;
            this._real.multiply3f(rx, ry, rz);
        }
    }

    protected onLod0Initiated(): void {
        const { sheet } = this._config;
        if (sheet != NOTFOUND_SHEET_ID) {
            if (!Dsm.LoadTexTaskLaunched[sheet]) {
                Dsm.LoadTexTaskLaunched[sheet] = true;
                const sharedMat = this.mesh0.getSharedMaterial(0);
                loadCelTexture(sharedMat, `dwarfs-${sheet}-high`, 'mainTexture', 'albedo', false);
                loadCelTexture(sharedMat, `dwarfs-${sheet}-high`, 'normalMap', 'normal', false);
            }
        }
    }

    public preloadRes(): void {
        const { sheet } = this._config;
        if (sheet != NOTFOUND_SHEET_ID) {
            if (!Dsm.LoadTexTaskLaunched[sheet]) {
                Dsm.LoadTexTaskLaunched[sheet] = true;
                core.notify(Task.Load.DYNAMIC_TEX, TaskNames.TEX_DSM_ALB.replace('idx', sheet + ''));
                core.notify(Task.Load.DYNAMIC_TEX, TaskNames.TEX_DSM_NRM.replace('idx', sheet + ''));
            }
        }
    }

    private _tiling: tiling;
    private _type: dsm;

    public static LoadTexTaskLaunched = [false, false, false];
}

const { Sheets: { DSM01_LOD_GIRDS, DSM2_LOD_GIRDS } } = Res;
const LOD_VALUES: Record<dsm, number[]> = {
    dwarf: [3, 1.5, 0.5, 0.2],
    satellite: [3, 1.5, 0.5, 0.2],
    minor: [3, 1.5, 0.5, 0.2],
}

const SMALLEST = 12.4e-6;   // diameter of Deimos (mkm) TO CHECK
const BIGGEST = 5.2682e-3;  // diameter of Ganymede (mkm)
const NEAREST = 0.2;
const FARTHEST = 0.5;